﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using HotShot.Entities;
using HotShot.Service.BusinessLogic;

namespace HotShot.Service
{
    static class Program
    {

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AllocConsole();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool SetConsoleTitle(string title);

        static bool ConsoleMode;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args)
        {
            foreach (var arg in args)
            {
                ParseArg(arg.Trim('-', '/'));
            }

            if (ConsoleMode)
            {
                RunConsole();
            }
            else
            {
                RunService();
            }
        }

        private static void ParseArg(string arg)
        {
            var parts = arg.Split(new[] { ':', '=' }, 2);
            parts[0] = parts[0].ToLower();

            switch (parts[0])
            {
                case "console":
                    ConsoleMode = true;
                    break;
                case "id":
                    ClusterProcessorLogic.Current.ProcessorId = parts[1];
                    break;
            }

        }

        static HotShotService hotShotService;

        static void RunService()
        {
            ServiceBase[] ServicesToRun;
            hotShotService = new HotShotService();

            ServicesToRun = new ServiceBase[] 
            { 
                hotShotService,
            };
            ServiceBase.Run(ServicesToRun);
        }

        static void RunConsole()
        {
            Dictionary<string, Action<string[]>> verbs = new Dictionary<string, Action<string[]>>
            {
                {"dumpnt", DumpNodeTable},
                {"dumpet", DumpEntityTable},
                {"dump", a => { DumpNodeTable(a); DumpEntityTable(a); }},
                {"toggle", ToggleWorker },
                {"delay", a => {
                    int i;
                    if(Int32.TryParse(a[1], out i)) 
                        Thread.Sleep(i);
                }},
            };

            AllocConsole();
            SetConsoleTitle("HotShot.Client " + ClusterProcessorLogic.Current.ProcessorId);
            Trace.Listeners.Add(new ConsoleTraceListener());
            hotShotService = new HotShotService();
            hotShotService.Initialize();

            var s = "foo"; // anything but an empty string
            
            // input commands - are processed before interactive mode starts
            List<string> ins = new List<string>();
            if (File.Exists("autoexec.txt")) ins.AddRange(File.ReadAllLines("autoexec.txt"));
            if (File.Exists("autoexec." + ClusterProcessorLogic.Current.ProcessorId + ".txt")) ins.AddRange(File.ReadAllLines("autoexec." + ClusterProcessorLogic.Current.ProcessorId + ".txt"));

            while (s != "")
            {
                if (ins.Count > 0)
                {
                    s = ins[0];
                    ins.RemoveAt(0);
                    Console.WriteLine(s);
                }
                else
                {
                    s = Console.ReadLine();
                }

                var ss = s.Split(' ');
                if (ss.Length > 0)
                {
                    Action<string[]> a;
                    if(verbs.TryGetValue(ss[0].ToLower(), out a)) {
                        a(ss);
                    }
                }
            }
            hotShotService.TearDown();
        }

        private static void DumpNodeTable(string[] args)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Node table:\r\n==============================================================\r\n");
            ClusterProcessorLogic.Current.GetKnownNodes(false, true).ForEach(
                n =>
                {
                    sb.AppendFormat("Node Id: {0} HashKey: {1} IsActive: {2} Ticks: {3}",
                        n.NodeId, n.HashKey, (n.IsActive ? 1 : 0), n.Ticks);
                    sb.AppendLine();
                });

            Trace.WriteLine(sb.ToString());
        }

        private static void DumpEntityTable(string[] args)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Entity table:\r\n==============================================================\r\n");
            EntityStoreLogic.Current.storageHash.ToList().ForEach(
                n =>
                {
                    sb.AppendFormat("Entity HashKey: {0} Ticks {1} Payload ({2}): {3}",
                        n.Key, 
                        n.Value.Ticks,
                        n.Value.Payload.Length,
                        n.Value.Payload
                        );
                    sb.AppendLine();
                });

            Trace.WriteLine(sb.ToString());
        }

        private static void ToggleWorker(string[] args) {
            switch(args[1].ToLower()) {
                case "globalgommunicationworker":
                case "global":
                case "gcw":
                    hotShotService.gcp.Disabled = !hotShotService.gcp.Disabled;
                    Trace.WriteLine("GlobalCommunicationWorker.Disabled = " + hotShotService.gcp.Disabled);
                    break;
                case "localgommunicationworker":
                case "local":
                case "lcw":
                    hotShotService.lcp.Disabled = !hotShotService.lcp.Disabled;
                    Trace.WriteLine("LocalCommunicationWorker.Disabled = " + hotShotService.lcp.Disabled);
                    break;
            }
        }
    }
}
